// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Equipment/LyraGameplayAbility_FromEquipment.h"

#include "LyraGameplayAbility_RangedWeapon.generated.h"

enum ECollisionChannel : int;

class APawn;
class ULyraRangedWeaponInstance;
class UObject;
struct FCollisionQueryParams;
struct FFrame;
struct FGameplayAbilityActorInfo;
struct FGameplayEventData;
struct FGameplayTag;
struct FGameplayTagContainer;

/** 定义技能追踪的起始位置和朝向 */
UENUM(BlueprintType)
enum class ELyraAbilityTargetingSource : uint8
{
	// 从玩家的摄像机朝向焦点
	CameraTowardsFocus,
	// 从Pawn的中心，沿Pawn的朝向
	PawnForward,
	// 从Pawn的中心，朝向摄像机焦点
	PawnTowardsFocus,
	// 从武器的枪口或位置，沿Pawn的朝向
	WeaponForward,
	// 从武器的枪口或位置，朝向摄像机焦点
	WeaponTowardsFocus,
	// 自定义蓝图指定的源位置
	Custom
};

/**
 * ULyraGameplayAbility_RangedWeapon
 * 由远程武器实例授予并与之关联的技能
 */
UCLASS()
class ULyraGameplayAbility_RangedWeapon : public ULyraGameplayAbility_FromEquipment
{
	GENERATED_BODY()

public:
	// 构造函数
	ULyraGameplayAbility_RangedWeapon(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

	/**
	 * 获取与此技能关联的武器实例。
	 * @return 返回 ULyraRangedWeaponInstance 指针
	 */
	UFUNCTION(BlueprintCallable, Category="Lyra|Ability")
	ULyraRangedWeaponInstance* GetWeaponInstance() const;

	//~UGameplayAbility 接口
	/**
	 * 重写的UGameplayAbility函数。检查技能是否可以被激活。
	 */
	virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags = nullptr, const FGameplayTagContainer* TargetTags = nullptr, OUT FGameplayTagContainer* OptionalRelevantTags = nullptr) const override;
	/**
	 * 重写的UGameplayAbility函数。激活技能。
	 */
	virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
	/**
	 * 重写的UGameplayAbility函数。结束技能。
	 */
	virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
	//~End of UGameplayAbility 接口

protected:
	// 远程武器开火输入数据结构
	struct FRangedWeaponFiringInput
	{
		// 追踪的起点
		FVector StartTrace;
		// 如果瞄准完美，追踪的终点
		FVector EndAim;
		// 如果瞄准完美，追踪的方向
		FVector AimDir;
		// 武器实例 / 武器数据源
		ULyraRangedWeaponInstance* WeaponData = nullptr;
		// 在此次追踪中，是否可以为命中播放子弹特效
		bool bCanPlayBulletFX = false;

		// 构造函数，初始化向量为零向量
		FRangedWeaponFiringInput()
			: StartTrace(ForceInitToZero)
			, EndAim(ForceInitToZero)
			, AimDir(ForceInitToZero)
		{
		}
	};

protected:
	/**
	 * 在命中结果数组中查找第一个Pawn命中结果。
	 * @param HitResults 命中结果数组
	 * @return 返回命中结果的索引，如果未找到则返回 INDEX_NONE
	 */
	static int32 FindFirstPawnHitResult(const TArray<FHitResult>& HitResults);

	/**
	 * 执行单次武器追踪，根据SweepRadius是否大于零决定是扫描还是射线追踪。
	 * @param StartTrace 追踪起点
	 * @param EndTrace 追踪终点
	 * @param SweepRadius 扫描半径
	 * @param bIsSimulated 是否是模拟的（预测）
	 * @param OutHitResults 输出的命中结果数组
	 * @return 返回最终的命中结果（通常是最后一个命中）
	 */
	FHitResult WeaponTrace(const FVector& StartTrace, const FVector& EndTrace, float SweepRadius, bool bIsSimulated, OUT TArray<FHitResult>& OutHitResults) const;

	/**
	 * WeaponTrace的包装器，处理先尝试射线追踪，如果没有命中且SweepRadius大于零则回退到扫描追踪。
	 * @param StartTrace 追踪起点
	 * @param EndTrace 追踪终点
	 * @param SweepRadius 扫描半径
	 * @param bIsSimulated 是否是模拟的（预测）
	 * @param OutHits 输出的命中结果数组
	 * @return 返回最终的命中结果
	 */
	FHitResult DoSingleBulletTrace(const FVector& StartTrace, const FVector& EndTrace, float SweepRadius, bool bIsSimulated, OUT TArray<FHitResult>& OutHits) const;

	/**
	 * 追踪一个弹匣中的所有子弹。
	 * @param InputData 开火输入数据
	 * @param OutHits 输出的命中结果数组
	 */
	void TraceBulletsInCartridge(const FRangedWeaponFiringInput& InputData, OUT TArray<FHitResult>& OutHits);

	/**
	 * 添加额外的追踪忽略Actor。可由子类重写以添加特定忽略规则。
	 * @param TraceParams 碰撞查询参数
	 */
	virtual void AddAdditionalTraceIgnoreActors(FCollisionQueryParams& TraceParams) const;

	/**
	 * 确定武器追踪使用的碰撞通道。
	 * @param TraceParams 碰撞查询参数
	 * @param bIsSimulated 是否是模拟的（预测）
	 * @return 返回碰撞通道
	 */
	virtual ECollisionChannel DetermineTraceChannel(FCollisionQueryParams& TraceParams, bool bIsSimulated) const;

	/**
	 * 执行本地目标定位，填充命中结果数组。
	 * @param OutHits 输出的命中结果数组
	 */
	void PerformLocalTargeting(OUT TArray<FHitResult>& OutHits);

	/**
	 * 获取武器目标定位的源位置（世界坐标）。
	 * @return 返回源位置向量
	 */
	FVector GetWeaponTargetingSourceLocation() const;
	/**
	 * 获取目标定位的变换（位置和旋转）。
	 * @param SourcePawn 源Pawn
	 * @param Source 目标定位源枚举
	 * @return 返回变换
	 */
	FTransform GetTargetingTransform(APawn* SourcePawn, ELyraAbilityTargetingSource Source) const;

	/**
	 * 当目标数据准备就绪时的回调函数。
	 * @param InData 目标数据句柄
	 * @param ApplicationTag 应用标签
	 */
	void OnTargetDataReadyCallback(const FGameplayAbilityTargetDataHandle& InData, FGameplayTag ApplicationTag);

	/**
	 * 开始远程武器目标定位过程（蓝图可调用）。
	 */
	UFUNCTION(BlueprintCallable)
	void StartRangedWeaponTargeting();

	/**
	 * 当目标数据准备就绪时调用（蓝图可实现事件）。
	 * @param TargetData 目标数据句柄
	 */
	UFUNCTION(BlueprintImplementableEvent)
	void OnRangedWeaponTargetDataReady(const FGameplayAbilityTargetDataHandle& TargetData);

private:
	// 目标数据准备就绪回调委托的句柄
	FDelegateHandle OnTargetDataReadyCallbackDelegateHandle;
};